package com.hornet.manager.system.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.hornet.commons.constants.BaseConst;
import com.hornet.commons.service.BaseService;
import com.hornet.commons.spring.SpringContextHolder;
import com.hornet.commons.spring.mail.MailBean;
import com.hornet.commons.spring.mail.MailKit;
import com.hornet.commons.utils.FreeMarkerKit;
import com.hornet.commons.utils.Md5Utils;
import com.hornet.commons.utils.PinyinUtil;
import com.hornet.commons.utils.PropertyUtils;
import com.hornet.commons.utils.SystemHelper;
import com.hornet.commons.web.model.AjaxResponse;
import com.hornet.manager.system.mapper.UserMapper;
import com.hornet.manager.system.model.User;
import com.hornet.manager.system.service.UserService;
import com.hornet.shiro.ShiroPasswordHelper;

@Service
public class UserServiceImpl extends BaseService<User> implements UserService {
	
	private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class) ;

	@Autowired
	private UserMapper mapper;
	
	@Autowired
	private FreeMarkerKit freeMarkerKit ;
	
	@Autowired
	private MailKit mailKit; 
	
	@Override
	public AjaxResponse add(User entity) {
		if(this.mapper.existsFileldValue(null, "account", entity.getAccount()) > 0) 
			return AjaxResponse.failMsg("该账号已存在！") ;
		if(this.mapper.existsFileldValue(null, "email", entity.getEmail()) > 0) 
			return AjaxResponse.failMsg("该邮箱地址已存在！") ;
		
		if(!StringUtils.isNotBlank(entity.getPassword())) {
			entity.setPassword(BaseConst.INIT_PASS); //系统默认密码
		}
		
		entity.setRandomSalt();
		entity.setPassword(ShiroPasswordHelper.encodePassword(entity.getPassword(), entity.getCredentialsSalt()));
		
		entity.setSpell(PinyinUtil.getPinYin(entity.getTruename()));
		return super.add(entity);
	}

	@Override
	public AjaxResponse update(User entity) {
		if(this.mapper.existsFileldValue(entity.getId(), "account", entity.getAccount()) > 0) 
			return AjaxResponse.failMsg("该账号已存在！") ;
		if(this.mapper.existsFileldValue(entity.getId(), "email", entity.getEmail()) > 0) 
			return AjaxResponse.failMsg("该邮箱地址已存在！") ;
		
		//不可编辑密码，密码修改使用其他方法来完成
		entity.setPassword(null);
		
		return super.update(entity);
	}
	
	@Override
	public AjaxResponse loginValid(String account, String password) {
		if(!StringUtils.isNotBlank(account) && !StringUtils.isNotBlank(password)) {
			return AjaxResponse.failMsg("账号或密码不能为空,请重新输入！") ;
		}
		
		AjaxResponse ajaxResponse = SpringContextHolder.getBean(AjaxResponse.class).reset() ;
		ajaxResponse.setStatus(false);
		
		Subject subject = SecurityUtils.getSubject();
		UsernamePasswordToken token = new UsernamePasswordToken(account, password);
		
		try {
			subject.login(token);
			
			User user = this.mapper.findByAccount(account) ;
			SystemHelper.setCurrentUser(user); // 保存当前用户登录信息
			
			//修改登录用户信息
			User entity = new User() ;
			entity.setId(user.getId());
			if(null == user.getLoginCount() || user.getLoginCount() < 1) {
				entity.setLoginCount(1);			//第一次登录
				entity.setFirstVisit(new Date());	//第一次登录时间
				entity.setLastVisit(new Date());	//最后一次登录时间
			} else {
				entity.setLoginCount(user.getLoginCount()+1);
			}
			entity.setPreviousVisit(user.getLastVisit());	//上一次登录时间
			entity.setLastVisit(new Date());				//最后一次登录时间
			
			super.updateNotNull(entity) ;
			
			ajaxResponse.setStatus(true);
			ajaxResponse.setMessage("登录成功");
			
		} catch (UnknownAccountException uae) {
			ajaxResponse.setMessage("该用户名不存在！");
		} catch (IncorrectCredentialsException ice) {
			ajaxResponse.setMessage("密码不正确");
		} catch (ExcessiveAttemptsException eae) {
			ajaxResponse.setMessage("密码错误次数太多，请确认用户名和密码！");
			HashMap<String, Object> map = new HashMap<String, Object>() ;
			map.put("showValidateCode", true);//需要输入验证码
			ajaxResponse.setObj(map);
		} catch (LockedAccountException lae) {
			ajaxResponse.setMessage("密码错误次数太多，账号已锁定，请10分钟后再试！");
		} catch (DisabledAccountException lae) {
			ajaxResponse.setMessage("账号已锁定，请联系管理员！");
		} catch (AuthenticationException ae) {
			ajaxResponse.setMessage("认证失败，请重新登录！");
		}

		return ajaxResponse;
	}

	@Override
	public User findByAccount(String account) {
		return this.mapper.findByAccount(account);
	}

	@Override
	public User findByEmail(String account) {
		return this.mapper.findByEmail(account);
	}

	@Override
	public AjaxResponse resetPassword(String password, Long[] ids) {
		AjaxResponse ajaxResponse = SpringContextHolder.getBean(AjaxResponse.class).reset() ; 
		if(StringUtils.isNotBlank(password)) {
			ajaxResponse.setMessage("用户重置后密码为：" + password);
		} else {
			password = BaseConst.INIT_PASS ;
			ajaxResponse.setMessage("用户重置后密码为：" + BaseConst.INIT_PASS);
		}
		if(null != ids) {
			for (Long id : ids) {
				User user = super.selectByKey(id) ;
				if(null != user) {
					User entity = new User() ;
					entity.setId(user.getId());
					entity.setRandomSalt();
					entity.setPassword(ShiroPasswordHelper.encodePassword(password, entity.getCredentialsSalt()));
					
					this.mapper.updateByPrimaryKeySelective(entity) ;
				} else {
					ajaxResponse.setStatus(false);
					ajaxResponse.setMessage("密码重置失败");
				}
			}
		} else {
			ajaxResponse.setStatus(false);
			ajaxResponse.setMessage("用户ID不能为空！");
		}
		
		return ajaxResponse;
	}

	
	
	
	@Override
	public AjaxResponse iforgotPassword(String email) {
		AjaxResponse ajaxResponse = SpringContextHolder.getBean(AjaxResponse.class).reset() ;
		ajaxResponse.setStatus(false);
		//先退出登录，等于清除Shiro中的认证缓存
		//否知修改密码后还是需要用原来的密码登录，只有用户的Session销毁后才可以用修改后的密码登录
		SystemHelper.logout();
		
		User user = this.mapper.findByEmail(email) ;
		if(null == user) {
			ajaxResponse.setMessage("该邮箱地址不存在！");
		} else {
			//生成密码找回的数字签名链接
			this.generatorSignatureLink(user) ;
			
			ajaxResponse.setStatus(true);
			ajaxResponse.setMessage("请登录邮箱进行验证！");
		}
		
		return ajaxResponse ;
	}
	
	public boolean generatorSignatureLink(User user) {
		String secretKey = UUID.randomUUID().toString(); // 密钥
		Date outDate = new Date(System.currentTimeMillis() + 30 * 60 * 1000);// 30分钟后过期
		long date = outDate.getTime()/ 1000 * 1000 ;
		String key = user.getAccount() + "$" + date + "$" + secretKey;
		String digitalSignature = Md5Utils.hash(key);// 数字签名
		
		//讲密码找回的数字签名和过期时间保存到数据库
		User record = new User();
		record.setId(user.getId());
		record.setIforgot_signature(digitalSignature);
		record.setIforgot_expires(new Date(date));
		this.mapper.updateByPrimaryKeySelective(record);
		
		String link = PropertyUtils.getValue("iforgot.link") + digitalSignature ;
		
		Map<String, Object> dataModel = new HashMap<String, Object>() ;
		dataModel.put("link", link) ;
		String html = this.freeMarkerKit.generator(dataModel, "iforgot.ftl") ;
		
		logger.debug("密码找回数字签名链接：" + link);
		
		//发送邮件
		MailBean mailBean = new MailBean() ;
		mailBean.setTo(user.getEmail());
		mailBean.setSubject(PropertyUtils.getValue("main.iforgot.subject"));
		mailBean.setContent(html);
		
		this.mailKit.sendAsync(mailBean);
		
		return true ;
	}

	@Override
	public AjaxResponse iforgotCheckLink(String digitalSignature) {
		AjaxResponse ajaxResponse = SpringContextHolder.getBean(AjaxResponse.class).reset();
		ajaxResponse.setStatus(false);
		
		if (null != digitalSignature && digitalSignature.equals("")) {
			ajaxResponse.setMessage("链接不完整,请重新生成！");
			return ajaxResponse;
		}
		
		User user = this.mapper.findBySignature(digitalSignature) ;
		if (null != user) {
			long outDateTime = (user.getIforgot_expires().getTime()/1000*1000) ;
			// 表示已经过期
			if (outDateTime <= System.currentTimeMillis()) {
				ajaxResponse.setStatus(false);
				ajaxResponse.setMessage("链接已经过期,请重新申请找回密码！");
				return ajaxResponse;
			}
			
			//链接检查通过
			ajaxResponse.setStatus(true);
			ajaxResponse.setObj(user);
			
		} else {
			ajaxResponse.setMessage("链接错误,或已过期,请重新申请找回密码.");
			return ajaxResponse;
		}
		return ajaxResponse;
	}
	
	@Override
	public AjaxResponse iforgotByResetPassword(Long id, String newPassword) {
		AjaxResponse ajaxResponse = SpringContextHolder.getBean(AjaxResponse.class).reset() ;
		ajaxResponse.setStatus(false);
		
		if(null != newPassword && !"".equals(newPassword)) {
			User user = super.selectByKey(id) ;
			
			if(null != user) {
				long outDateTime = (user.getIforgot_expires().getTime()/1000*1000) ;
				//在密码找回页面待的时间太长，超过时间都未按提交按钮。超过时间再按的话还是要重新申请
				if (outDateTime <= System.currentTimeMillis()) {
					ajaxResponse.setMessage("修改密码超时，请重新申请密码找回！");
					return ajaxResponse;
				}
				
				User record = new User() ;
				record.setId(id);
				record.setRandomSalt();
				record.setPassword(ShiroPasswordHelper.encodePassword(newPassword, record.getCredentialsSalt()));
				record.setIforgot_expires(null);
				record.setIforgot_signature(null);
				record.setChange_pass_date(new Date());
				
				this.mapper.updateByPrimaryKeySelective(record) ;
				
				ajaxResponse.setStatus(true);
				ajaxResponse.setMessage("重设密码成功，返回登录页面");
				return ajaxResponse;
			} else {
				ajaxResponse.setMessage("用户不存在或链接错误，请重新申请密码找回！");
				return ajaxResponse;
			}
		}
		
		return ajaxResponse ;
	}
}
